#include "sys.h"
#include "net.h"
#include "log.h"
#include "cJSON.h"
#include "devinfo.h"

DevInfo_t devInfo = { 0 };
void devinfo_update_systime(uint32_t sec){
    int diff_sec = 0;
    struct timeval local_tm;

    gettimeofday(&local_tm, NULL);
    diff_sec = local_tm.tv_sec - sec;

    if(Positive(diff_sec) < 10)
        return;

    if(is_hg261gs()){
        log_trace("Update Systime.");
        sys_time_update(sec + (8 * 3600), 0);
    }
}
int devinfo_is_bridge(){
    if(is_hg261gs()){
        return hg261gs_is_bridge();
    }else if(is_pt622g()){
        return pt622g_is_bridge();
    }else if(is_TEWA500AG()){
        return TEWA500AG_is_bridge();
    }
    return 0;
}
int devinfo_has_internet_r(){
    if(is_hg261gs()){
        return hg261gs_has_internet();
    }else if(is_pt622g()){
        return pt622g_has_internet();
    }else if(is_TEWA500AG()){
        return TEWA500AG_has_internet();
    }
    return 1;
}
int devinfo_get_internet_r_usr_pwd(char *pppoe_usr, char *pppoe_pwd){
    if(is_hg261gs()){
        return hg261gs_get_internet_r_pwd(pppoe_usr, pppoe_pwd);
    }else if(is_pt622g()){
        return pt622g_get_internet_r_pwd(pppoe_usr, pppoe_pwd);
    }else if(is_TEWA500AG()){
        return TEWA500AG_get_internet_r_pwd(pppoe_usr, pppoe_pwd);
    }
    return 0;
}
void devinfo_add_pppoe_dial(char* usrname, char* pwd)
{
    int ret = 0;
    char cmd[128] = { 0 };

    if (is_hg261gs()) {
        log_trace("HG261GS add pppoe dial shell");
        //如果HG261GS有网络连接，则拨号脚本不会添加拨号连接
        if(hg261gs_is_bridge()){
            sprintf(cmd, "./hg261gs_pppoe.sh add %s %s", usrname, pwd);
            log_trace("%s", cmd);
            system(cmd);
        }
    } else if (is_pt622g()) {
        log_trace("PT622G add pppoe dial shell");
        //如果PT622G是桥模式，才添加拨号连接
        if (pt622g_is_bridge()) {
            sprintf(cmd, "./pt622g_pppoe.sh -c add -t pppoe -v 41 -u %s -p %s", usrname, pwd);
            log_trace("%s", cmd);
            ret = system(cmd);
            log_trace("ret:%d", ret);
        }
    }else if(is_TEWA500AG()){
        log_trace("TEWA_500AG add pppoe dial shell");
        if(TEWA500AG_is_bridge()){
            sprintf(cmd, "qoecmd wan_ty add %s %s 41", usrname, pwd);
            log_trace("%s", cmd);
            system(cmd);
        }
    }
}
void devinfo_del_pppoe_dial(char* usrname, char* pwd)
{
    int ret = 0;
    char cmd[256] = { 0 };

    if (is_hg261gs()) {
        log_trace("HG261GS del pppoe dial shell");
        sprintf(cmd, "./hg261gs_pppoe.sh del %s %s", usrname, pwd);
        log_trace("%s", cmd);
        system(cmd);
    } else if (is_pt622g()) {
        log_trace("PT622G del pppoe dial shell");

        system("/userfs/bin/tcapi set WanInfo_WanPVC VLANID 41");
        log_trace("/userfs/bin/tcapi set WanInfo_WanPVC VLANID 41");

        system("/userfs/bin/tcapi set WanInfo_WanPVC DOT1P 0");
        log_trace("/userfs/bin/tcapi set WanInfo_WanPVC DOT1P 0");

        sprintf(cmd, "./pt622g_pppoe.sh -c del -v 41 -u %s -p %s", usrname, pwd);
        log_trace("%s", cmd);
        ret = system(cmd);
        log_trace("ret:%d", ret);
        
    }else if(is_TEWA500AG()){
        log_trace("TEWA_500AG del pppoe dial shell");
        sprintf(cmd, "qoecmd wan_ty del %s %s 41", usrname, pwd);
        log_trace("%s", cmd);
        system(cmd);
        
    }
}

int devinfo_monitor_net_rate(DevInfo_t* devinfo){
    int ret = 0;
    int fd = 0;
    fd_set rdfds;
    uint32_t total_len = 0;
    char buf[0xffff] = {0};
    struct timeval start_tm, now_tm, timeout;

    if(devinfo->forbidCheckBackgroudFlow == 1){
        return 0;
    }

    if(is_hg261gs()){
        hg261gs_enable_mirror(devinfo);
    }

    fd = socket_packet_new();

    gettimeofday(&start_tm, NULL);
    while(1){
        FD_ZERO(&rdfds);
        FD_SET(fd, &rdfds);
        timeout.tv_sec = 0;
        timeout.tv_usec = 10;
        ret = select(fd + 1, &rdfds, NULL, NULL, &timeout);
        if(ret < 0){
            log_syserr("dev monitor rate select error.");
            break;
        }
        gettimeofday(&now_tm, NULL);
        if((now_tm.tv_sec * 1000 * 1000 + now_tm.tv_usec) - (start_tm.tv_sec * 1000 * 1000 + start_tm.tv_usec) >= (1000 * 1000)){
            break;
        }
        if(FD_ISSET(fd, &rdfds)){
            ret = recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL);
            if(ret < 0){
                log_syserr("monitor net rate rcv failed.");
                continue;
            }
            total_len += ret;
        }
        
    }
    log_trace("total_len:%d", total_len);
    close(fd);

    if(is_hg261gs()){
        hg261gs_disable_mirror(devinfo);
    }
    return total_len;
}

void devinfo_get_addrinfo(DevInfo_t* devinfo)
{
    struct in_addr ip;
    uint8_t mac[6];

    getifaddr(devinfo->ifname, (void*)&ip, "ip");
    if (is_hg261gs()) {
        log_trace("hg261gs");
        hg261gs_get_mac(mac);
    } else if (is_pt622g()) {
        log_trace("pt622g");
        pt622g_get_mac(mac);
    }else if(is_TEWA500AG()){
        log_trace("TEWA500AG");
        TEWA500AG_get_mac(mac);
    }else if(isHiWIFI()){
        getifaddr("eth2.2", mac, "mac");
    } else {
        log_trace("Linux");
        getifaddr(devinfo->ifname, mac, "mac");
    }

    strcpy(devinfo->ip, inet_ntoa(ip));
    sprintf(devinfo->mac, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
static char* _cpu_info(char* buf)
{
    char *delim = ":", *ptr, *saveptr;
    ptr = strtok_r(buf, delim, &saveptr);
    ptr = strtok_r(NULL, delim, &saveptr);
    ptr[strlen(ptr) - 1] = '\0';
    return ptr;
}
void get_cpu_info(char* cpuinfo)
{
    FILE* fp;
    char buf[128];

    fp = fopen(PROC_CPU_INFO, "r");
    while (fgets(buf, sizeof(buf), fp) != NULL) {
        if (is_pt622g()) { //友华PT622G
            if (strstr(buf, "system type")) {
                strcpy(cpuinfo, _cpu_info(buf));
                break;
            }
        } else if (strstr(buf, "Processor")) {
            strcpy(cpuinfo, _cpu_info(buf));
            break;
        } else if (strstr(buf, "model name")) {
            strcpy(cpuinfo, _cpu_info(buf));
            break;
        } else if (strstr(buf, "cpu model")) {
            strcpy(cpuinfo, _cpu_info(buf));
            break;
        }
    }
    fclose(fp);
}
void get_os_version(char* buf)
{
#define PROC_LINUX_VERSION "/proc/version"

    FILE* fp;
    char buffer[32] = { 0 };

    fp = popen("cat " PROC_LINUX_VERSION " | cut -d' ' -f3", "r");
    fgets(buffer, sizeof(buffer), fp);
    pclose(fp);
    buffer[strlen(buffer) - 1] = 0;
    strcpy(buf, buffer);
}
void get_mem_info(char* buf)
{
    struct sysinfo s_info;

    sysinfo(&s_info);
    sprintf(buf, "%ld", s_info.totalram / 1024 / 1024);
}
void get_misc_info(DevInfo_t* devinfo)
{
    struct tm *p, tm_p;
    struct sysinfo s_info;
    time_t now, uptime;

    sysinfo(&s_info);
    now = time(NULL);
    uptime = now - s_info.uptime;
    localtime_r(&uptime, &tm_p);
    p = &tm_p;

    sprintf(devinfo->upTime, "%d-%02d-%02d %02d:%02d:%02d",
        1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
    strcpy(devinfo->insertTime, devinfo->upTime);

    sprintf(devinfo->startUpTime, "%ld", (long)s_info.uptime);
}
static int check_is_wifi(char* ifname)
{
    return strstr(ifname, "wlan") > 0 ? 1 : 0;
}

void load_devinfo(DevInfo_t* devinfo)
{

    devinfo->is_wifi = check_is_wifi(devinfo->ifname);
    devinfo_get_addrinfo(devinfo);
#if __ANDROID__
    extern void android_get_devinfo(DevInfo_t*);
    android_get_devinfo(devinfo);
#elif __LINUX_OS__
    if (is_hg261gs()) {
        hg261gs_get_devinfo(devinfo);
    } else if (is_pt622g()) {
        pt622g_get_devinfo(devinfo);
    }else if(is_TEWA500AG()){
        TEWA500AG_get_devinfo(devinfo);
    } else {
        extern void linux_get_devinfo(DevInfo_t*);
        linux_get_devinfo(devinfo);
    }
#endif
        get_cpu_info(devinfo->cpu);
        get_mem_info(devinfo->mem);
        get_misc_info(devinfo);

}

cJSON* devinfo2cjson(DevInfo_t* devinfo, cJSON* root)
{
    cJSON* _root;

    if (!root)
        _root = cJSON_CreateObject();
    else
        _root = root;

    cJSON_AddStringToObject(_root, "clientId", devinfo->mac);
    cJSON_AddStringToObject(_root, "gatewaySN", devinfo->gatewaySN);
    cJSON_AddStringToObject(_root, "loid", devinfo->loid);
    cJSON_AddStringToObject(_root, "loidKey", devinfo->loidKey);
    cJSON_AddNumberToObject(_root, "clientPattern", devinfo->clientPattern);
    cJSON_AddNumberToObject(_root, "flashSize", devinfo->flashSize);
    cJSON_AddStringToObject(_root, "accountCode", devinfo->mac);
    cJSON_AddStringToObject(_root, "stbIp", devinfo->ip);
    // cJSON_AddStringToObject(_root, "wlanNumberIp", "");
    // cJSON_AddStringToObject(_root, "mac2", "");
    cJSON_AddNumberToObject(_root, "netModel", (devinfo->is_wifi ? 1 : 3));
    // cJSON_AddStringToObject(_root, "clientType", devinfo->dev_type);
    cJSON_AddStringToObject(_root, "clientModel", devinfo->model);
    cJSON_AddStringToObject(_root, "clientVersion", devinfo->sw_version);
    cJSON_AddStringToObject(_root, "clientFactory", devinfo->factory);
    cJSON_AddStringToObject(_root, "clientMem", devinfo->mem);
    cJSON_AddStringToObject(_root, "clientCpu", devinfo->cpu);
    cJSON_AddStringToObject(_root, "osType", devinfo->osType);
    cJSON_AddStringToObject(_root, "osVersion", devinfo->osVersion);
    cJSON_AddStringToObject(_root, "upTime", devinfo->upTime);
    cJSON_AddStringToObject(_root, "insertTime", devinfo->insertTime);
    cJSON_AddStringToObject(_root, "startUpTime", devinfo->startUpTime);
    return _root;
}
